/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.jm.financeiro.filter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.docx4j.XmlUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.ContentAccessor;
import org.docx4j.wml.P;
import org.docx4j.wml.Tbl;
import org.docx4j.wml.Text;
import org.docx4j.wml.Tr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 *
 * @author joao
 */
public class word {

    public WordprocessingMLPackage template;
    private final UploadArquivo arquivo = new UploadArquivo();
    private DocumentBuilderFactory dbf;
    private DocumentBuilder db;
    private Document doc;

    public static void main(String[] args) throws Exception {
        word app = new word();
        // app.newWordDoc("testfile", "Hello World!");
    }

    public void gravaArquivo(String cArqTemplate, String cArqDestino, String cConteudo) throws Exception {
        template = getTemplate(cArqTemplate);
        replaceNegrito("SJ_EX1", cConteudo, template, template.getMainDocumentPart());
        //replaceParagraph("SJ_EX1", cConteudo, template, template.getMainDocumentPart());
        writeDocxToStream(template, cArqDestino);
    }

    public void newWordDoc(String filename, String fileContent) throws Exception {
        XWPFDocument document = new XWPFDocument();
        XWPFParagraph tmpParagraph = document.createParagraph();
        XWPFRun tmpRun = tmpParagraph.createRun();
        tmpRun.setText(fileContent);
        tmpRun.setFontSize(8);
        try (FileOutputStream fos = new FileOutputStream(new File(filename + ".docx"))) {
            document.write(fos);
        }
    }

    public WordprocessingMLPackage getTemplate(String name) throws Docx4JException, FileNotFoundException {
        WordprocessingMLPackage template = WordprocessingMLPackage.load(new FileInputStream(new File(name)));
        return template;
    }

    public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
        List<Object> result = new ArrayList<Object>();
        if (obj instanceof JAXBElement) {
            obj = ((JAXBElement<?>) obj).getValue();
        }

        if (obj.getClass().equals(toSearch)) {
            result.add(obj);
        } else if (obj instanceof ContentAccessor) {
            List<?> children = ((ContentAccessor) obj).getContent();
            for (Object child : children) {
                result.addAll(getAllElementFromObject(child, toSearch));
            }

        }
        return result;
    }

    public void replacePlaceholder(WordprocessingMLPackage template, String name, String placeholder) {
        List<Object> texts = getAllElementFromObject(template.getMainDocumentPart(), Text.class);

        for (Object text : texts) {
            Text textElement = (Text) text;
            if (textElement.getValue().equals(placeholder)) {
                textElement.setValue(name);
            }
        }
    }

    public void writeDocxToStream(WordprocessingMLPackage template, String target) throws IOException, Docx4JException {
        File f = new File(target);
        template.save(f);
    }

    public void replaceParagraph(String placeholder, String textToAdd, WordprocessingMLPackage template, ContentAccessor addTo) throws JAXBException {
        // 1. get the paragraph
        List<Object> paragraphs = getAllElementFromObject(template.getMainDocumentPart(), P.class);

        boolean lPassa = false;
        String str = "";

        P toReplace = null;
        for (Object p : paragraphs) {
            List<Object> texts = getAllElementFromObject(p, Text.class);
            for (Object t : texts) {
                Text content = (Text) t;
                if (content.getValue().equals(placeholder)) {
                    toReplace = (P) p;
                    break;
                }
            }
        }
        // we now have the paragraph that contains our placeholder: toReplace
        // 2. split into seperate lines
        String as[] = StringUtils.splitPreserveAllTokens(textToAdd, '\n');

        for (String ptext : as) {
            lPassa = ptext.contains("#B");
            // 3. copy the found paragraph to keep styling correct
            P copy = (P) XmlUtils.deepCopy(toReplace);

            // replace the text elements from the copy
            List<?> texts = getAllElementFromObject(copy, Text.class);
            if (texts.size() > 0) {
                Text textToReplace = (Text) texts.get(0);
                textToReplace.setValue(ptext);

                if (lPassa) {
                    int nInicial = ptext.indexOf("#B");
                    int nFinal = ptext.indexOf("#/B");
                    String cTextoInicial = "";
                    String cTextoNegrito = "";
                    String cTextoFinal = "";

                    if (nInicial == 0) {
                        ptext = ptext.replace("#B", "<w:b /></w:rPr><w:t>");
                        ptext = ptext.replace("#/B", "</w:t></w:r></w:p>");
                        str = "<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" >"
                                + "<w:r><w:rPr><w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/><w:sz w:val=\"16\"/>".concat(ptext);
                    } else {
                        cTextoInicial = "</w:rPr><w:t>" + ptext.substring(0, nInicial) + "</w:t>";
                        str = "<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" ><w:r><w:rPr><w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                                + "<w:sz w:val=\"16\"/>"
                                + cTextoInicial + "</w:r></w:p>";
                        addTo.getContent().add(org.docx4j.XmlUtils.unmarshalString(str));

                        cTextoNegrito = ptext.substring(nInicial, nFinal + 3);
                        cTextoNegrito = cTextoNegrito.replace("#B", "<w:b /></w:rPr><w:t>");
                        cTextoNegrito = cTextoNegrito.replace("#/B", "</w:t>");

                        str = "<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" ><w:r><w:rPr><w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                                + "<w:sz w:val=\"16\"/>"
                                + cTextoNegrito + "</w:r></w:p>";
                        addTo.getContent().add(org.docx4j.XmlUtils.unmarshalString(str));

                        ptext = ptext.replace("#/B", "");
                        cTextoFinal = ptext.substring(nFinal);

                        if (cTextoFinal.trim().length() > 0) {
                            cTextoFinal = "</w:rPr><w:t>" + ptext.substring(nFinal) + "</w:t></w:r></w:p>";
                        } else {
                            cTextoFinal = "</w:rPr></w:r></w:p>";
                        }
                        str = "<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" ><w:r><w:rPr><w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                                + "<w:sz w:val=\"16\"/>"
                                + cTextoFinal;
                    }
                }
            }

            // add the paragraph to the document
            if (lPassa) {
                addTo.getContent().add(org.docx4j.XmlUtils.unmarshalString(str));
            } else {
                addTo.getContent().add(copy);
            }

        }

        // 4. remove the original one
        ((ContentAccessor) toReplace.getParent()).getContent().remove(toReplace);

    }

    public void replaceTable(String[] placeholders, List<Map<String, String>> textToAdd,
            WordprocessingMLPackage template) throws Docx4JException, JAXBException {
        List<Object> tables = getAllElementFromObject(template.getMainDocumentPart(), Tbl.class);

        // 1. find the table
        Tbl tempTable = getTemplateTable(tables, placeholders[0]);
        List<Object> rows = getAllElementFromObject(tempTable, Tr.class);

        // first row is header, second row is content
        if (rows.size() == 2) {
            // this is our template row
            Tr templateRow = (Tr) rows.get(1);

            for (Map<String, String> replacements : textToAdd) {
                // 2 and 3 are done in this method
                addRowToTable(tempTable, templateRow, replacements);
            }

            // 4. remove the template row
            tempTable.getContent().remove(templateRow);
        }
    }

    public Tbl getTemplateTable(List<Object> tables, String templateKey) throws Docx4JException, JAXBException {
        for (Object tbl : tables) {
            List<?> textElements = getAllElementFromObject(tbl, Text.class);
            for (Object text : textElements) {
                Text textElement = (Text) text;
                if (textElement.getValue() != null && textElement.getValue().equals(templateKey)) {
                    return (Tbl) tbl;
                }
            }
        }
        return null;
    }

    public static void addRowToTable(Tbl reviewtable, Tr templateRow, Map<String, String> replacements) {
        Tr workingRow = (Tr) XmlUtils.deepCopy(templateRow);
        List<?> textElements = getAllElementFromObject(workingRow, Text.class);
        for (Object object : textElements) {
            Text text = (Text) object;
            String replacementValue = (String) replacements.get(text.getValue());
            if (replacementValue != null) {
                text.setValue(replacementValue);
            }
        }

        reviewtable.getContent().add(workingRow);
    }

    private static org.docx4j.wml.P createParagraph(String paragraphContent, boolean bold) {
        org.docx4j.wml.ObjectFactory factory = Context.getWmlObjectFactory();
        org.docx4j.wml.P p = factory.createP();

        org.docx4j.wml.R run = factory.createR();
        //p.getContent().add(run);

        //org.docx4j.wml.Text text = factory.createText();
        //text.setValue(paragraphContent);
        //run.getContent().add(text);
        if (bold) {
            org.docx4j.wml.RPr rpr = factory.createRPr();
            org.docx4j.wml.BooleanDefaultTrue b = new org.docx4j.wml.BooleanDefaultTrue();
            b.setVal(true);
            rpr.setB(b);
            run.setRPr(rpr);
        }

        return p;
    }

    public void replaceBold(String placeholder, String textToAdd, WordprocessingMLPackage template, ContentAccessor addTo) throws JAXBException {

        try {
            String cCaminho = this.arquivo.getRealPath() + "\\documento\\";
            String cArquivoXML = cCaminho + "modelo_timbrado_pcta.xml";
            String cArquivoDOCX = cCaminho + "teste_pcta.docx";

            doc = db.parse(cArquivoXML);
            //Passo 1: obter o elemento raiz
            Element raiz = doc.getDocumentElement();

            //Passo 2: localizar os elementos filhos da agenda
            NodeList listaBody = raiz.getElementsByTagName("w:body");

            Element element = doc.createElement("contato");

        } catch (Exception exc) {
            exc.printStackTrace();
            throw new RuntimeException(exc);
        }
        /*
         String cCaminho = this.arquivo.getRealPath() + "\\documento\\";
         String cArquivo = cCaminho + "modelo_timbrado_pcta.xml";

         try {
         doc = db.parse(cArquivo);
         //Passo 1: obter o elemento raiz
         // Element raiz = doc.getDocumentElement();

         //Passo 2: localizar os elementos filhos da agenda
         //NodeList listaContatos = raiz.getElementsByTagName("contato");
            
         addTo.getContent().add(doc);
         } catch (SAXException e) {
         System.out.println("Problema ao fazer o parse do arquivo.");
         } catch (IOException e) {
         System.out.println("O arquivo nao pode ser lido.");
         }
         */
    }

    public void replaceNegrito(String placeholder, String textToAdd, WordprocessingMLPackage template, ContentAccessor addTo) throws JAXBException {
        // 1. get the paragraph
        List<Object> paragraphs = getAllElementFromObject(template.getMainDocumentPart(), P.class);

        boolean lPassa = false;
        String str = "";

        P toReplace = null;
        for (Object p : paragraphs) {
            List<Object> texts = getAllElementFromObject(p, Text.class);
            for (Object t : texts) {
                Text content = (Text) t;
                if (content.getValue().equals(placeholder)) {
                    toReplace = (P) p;
                    break;
                }
            }
        }
        // we now have the paragraph that contains our placeholder: toReplace
        // 2. split into seperate lines
        String as[] = StringUtils.splitPreserveAllTokens(textToAdd, '\n');

        for (String ptext : as) {
            lPassa = ptext.contains("#B");
            // 3. copy the found paragraph to keep styling correct
            P copy = (P) XmlUtils.deepCopy(toReplace);

            // replace the text elements from the copy
            List<?> texts = getAllElementFromObject(copy, Text.class);
            if (texts.size() > 0) {
                Text textToReplace = (Text) texts.get(0);
                textToReplace.setValue(ptext);

                if (lPassa) {
                    int nInicial = ptext.indexOf("#B");
                    int nFinal = ptext.indexOf("#/B");
                    String cTextoInicial = "";
                    String cTextoNegrito = "";
                    String cTextoFinal = "";

                    ptext = ptext.replace("#B", "");
                    ptext = ptext.replace("#/B", "");

                    if (nInicial == 0) {
                        str = "<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"
                                + "<w:pPr>"
                                + "<w:pStyle w:val=\"SemEspaamento\"/>"
                                + "<w:rPr>"
                                + "<w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                                + "<w:smallCaps/>"
                                + "<w:sz w:val=\"16\"/>"
                                + "<w:szCs w:val=\"16\"/>"
                                + "</w:rPr>"
                                + "</w:pPr>"
                                + "<w:r>"
                                + "<w:rPr>"
                                + "<w:pStyle w:val=\"SemEspaamento\"/>"
                                + "<w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                                + "<w:b/>"
                                + "<w:smallCaps/>"
                                + "<w:sz w:val=\"16\"/>"
                                + "<w:szCs w:val=\"16\"/>"
                                + "</w:rPr>"
                                + "<w:t xml:space=\"preserve\">" + ptext + "</w:t>"
                                + "</w:r>"
                                + "</w:p>";
                    } else {
                        cTextoInicial = ptext.substring(0, nInicial);
                        cTextoNegrito = ptext.substring(nInicial, nFinal-2);
                        cTextoFinal = ptext.substring(nFinal-2);

                        str = "<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"
                                + "<w:pPr>"
                                + "<w:pStyle w:val=\"Normal\"/>"
                                + "<w:rPr>"
                                + "<w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                                + "<w:smallCaps/>"
                                + "<w:sz w:val=\"16\"/>"
                                + "<w:szCs w:val=\"16\"/>"
                                + "</w:rPr>"
                                + "</w:pPr>"
                                + "<w:r>"
                                + "<w:rPr>"
                                + "<w:pStyle w:val=\"Normal\"/>"
                                + "<w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                                + "<w:smallCaps/>"
                                + "<w:sz w:val=\"16\"/>"
                                + "<w:szCs w:val=\"16\"/>"
                                + "</w:rPr>"
                                + "<w:t xml:space=\"preserve\">" + cTextoInicial + "</w:t>"
                                + "</w:r>"
                                + "<w:r>"
                                + "<w:rPr>"
                                + "<w:pStyle w:val=\"Normal\"/>"
                                + "<w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                                + "<w:b/>"
                                + "<w:smallCaps/>"
                                + "<w:sz w:val=\"16\"/>"
                                + "<w:szCs w:val=\"16\"/>"
                                + "</w:rPr>"
                                + "<w:t xml:space=\"preserve\">" + cTextoNegrito + "</w:t>"
                                + "</w:r>"
                                + "<w:r>"
                                + "<w:rPr>"
                                + "<w:pStyle w:val=\"Normal\"/>"
                                + "<w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                                + "<w:smallCaps/>"
                                + "<w:sz w:val=\"16\"/>"
                                + "<w:szCs w:val=\"16\"/>"
                                + "</w:rPr>"
                                + "<w:t xml:space=\"preserve\">" + cTextoFinal + "</w:t>"
                                + "</w:r>"
                                + "</w:p>";

                    }
                } else {
                    str = "<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"
                            + "<w:pPr>"
                            + "<w:pStyle w:val=\"Normal\"/>"
                            + "<w:rPr>"
                            + "<w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                            + "<w:smallCaps/>"
                            + "<w:sz w:val=\"16\"/>"
                            + "<w:szCs w:val=\"16\"/>"
                            + "</w:rPr>"
                            + "</w:pPr>"
                            + "<w:r>"
                            + "<w:rPr>"
                            + "<w:pStyle w:val=\"Normal\"/>"
                            + "<w:rFonts w:ascii=\"Verdana\" w:hAnsi=\"Verdana\"/>"
                            + "<w:smallCaps/>"
                            + "<w:sz w:val=\"16\"/>"
                            + "<w:szCs w:val=\"16\"/>"
                            + "</w:rPr>"
                            + "<w:t xml:space=\"preserve\">" + ptext + "</w:t>"
                            + "</w:r>"
                            + "</w:p>";
                }
            }

            // add the paragraph to the document
            //if (lPassa) {
            addTo.getContent().add(org.docx4j.XmlUtils.unmarshalString(str));
            //} else {
            //addTo.getContent().add(copy);
            //}

        }

        // 4. remove the original one
        ((ContentAccessor) toReplace.getParent()).getContent().remove(toReplace);

    }
}
